package com.tjetc;

import java.util.concurrent.*;

@SuppressWarnings("all")
public class _11ThreadPool {

    public static void main(String[] args) {
        /*
            线程池：是一种池化的技术
            池化种类： 线程池 连接池 内存池 对象池
            什么是池化？
                提前保存大量的资源，提高资源利用率，提高性能。
                节省了频繁创建和销毁线程的开销
            核心：主要研究ThreadPoolExecutor线程池中的7大参数

            1.corePoolSize: 核心线程数 初始的时候希望这个线程池创建几个线程
            2.maximumPoolSize：最大线程数 最多能创建几个线程
            3.keepAliveTime：非核心线程的空闲时间 如果超过空闲时间 销毁
            4.unit: 时间单位
            5.workQueue：多余任务等待队列 任务处理不完 等着
            6.threadFactory： 线程工厂 创建线程时有一些统一要求，和一些个性要求
            7.handler：拒绝策略

            常见的线程池：
                FixedThreadPool：固定并发任务
                CachedThreadPool：短时异步任务
                SingleThreadExecutor：单线程顺序执行
                ScheduledThreadPool：定时/周期性任务
                ForkJoinPool：分治/递归任务
            可以通过Executors.的方法找到相关的静态内部类 JDK给我们提供好的线程池

            corePoolSize – the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
            maximumPoolSize – the maximum number of threads to allow in the pool
            keepAliveTime – when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
            unit – the time unit for the keepAliveTime argument
            workQueue – the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.
            threadFactory – the factory to use when the executor creates a new thread
            handler – the handler to use when execution is blocked because the thread bounds and queue capacities are reached



    核心和最大池大小
        ThreadPoolExecutor将根据corePoolSize和maximumPoolSize设置的边界自动调整池大小。当在方法execute(Runnable) 中提交新任务时，
        如果正在运行的线程少于 corePoolSize ，则会创建一个新线程来处理请求，即使其他工作线程处于空闲状态也是如此。
        否则，如果运行的线程少于 maximumPoolSize，则只有在队列已满时才会创建一个新线程来处理请求。
        通过将 corePoolSize 和 maximumPoolSize 设置为相同，您可以创建一个固定大小的线程池。
        通过将 maximumPoolSize 设置为一个本质上无限制的值，例如 Integer.MAX_VALUE ，您允许池容纳任意数量的并发任务。
        最典型的是，核心和最大池大小仅在构造时设置，但它们也可以使用 setCorePoolSize(int) 和 setMaximumPoolSize(int) 动态更改。
    按需施工
        默认情况下，即使是核心线程也仅在新任务到达时才最初创建和启动，但这可以使用方法 prestartCoreThread() 或 prestartAllCoreThreads() 动态覆盖。
        如果您使用非空队列构建池，您可能希望预启动线程。
    创建新线程
        使用 ThreadFactory 创建新线程。
        如果没有另外指定，将使用 Executors.defaultThreadFactory() ，它创建的线程都处于相同的 ThreadGroup 并具有相同的 NORM_PRIORITY 优先级和非守护程序状态。
        通过提供不同的 ThreadFactory，您可以更改线程的名称、线程组、优先级、守护程序状态等。
        如果 ThreadFactory 在通过从 newThread 返回 null 询问时无法创建线程，执行程序将继续，但可能无法执行任何任务。
        线程应该拥有“modifyThread”RuntimePermission。如果工作线程或使用该池的其他线程不具备此权限，则服务可能会降级：
        配置更改可能无法及时生效，并且关闭的池可能仍处于可以终止但未完成的状态。
    保活次数
        如果池中当前有超过 corePoolSize 个线程，则多余的线程如果空闲时间超过 keepAliveTime将被终止。
        这提供了一种在池未被积极使用时减少资源消耗的方法。如果稍后池变得更加活跃，将构造新的线程。也可以使用方法 setKeepAliveTime(long, TimeUnit) 动态更改此参数。
        使用 Long.MAX_VALUE TimeUnit.NANOSECONDS 的值可以有效地禁止空闲线程在关闭之前终止。默认情况下，仅当线程数超过 corePoolSize 时才应用保持活动策略，
        但方法 allowCoreThreadTimeOut(boolean) 也可用于将此超时策略应用于核心线程，只要 keepAliveTime 值不为零即可。
    排队
        任何 BlockingQueue 可用于传输和保留提交的任务。此队列的使用与池大小交互：
            如果正在运行的线程少于 corePoolSize，则 Executor 总是更喜欢添加新线程而不是排队。
            如果 corePoolSize 或更多线程正在运行，则 Executor 总是更喜欢排队请求而不是添加新线程。
            如果请求无法排队，则会创建一个新线程，除非这会超过 maximumPoolSize，在这种情况下，任务将被拒绝。
    排队的一般策略有以下三种：
        Direct handoffs. 工作队列的一个很好的默认选择是 SynchronousQueue ，它将任务交给线程而不用其他方式持有它们。
            在这里，如果没有线程立即可用于运行任务，尝试将任务排队将失败，因此将构造一个新线程。
            该策略在处理可能具有内部依赖性的请求集时避免了锁定。
            直接切换通常需要无限的 maximumPoolSizes 以避免拒绝新提交的任务。
            当命令的平均到达速度继续快于它们的处理速度时，这反过来又承认了无限线程增长的可能性。
        Unbounded queues. 使用无界队列（例如没有预定义容量的 LinkedBlockingQueue ）将导致新任务在所有 corePoolSize 线程都忙时在队列中等待。
            因此，将永远不会创建超过 corePoolSize 个线程。 （因此 maximumPoolSize 的值没有任何影响。）当每个任务完全独立于其他任务时，这可能是合适的，
            因此任务不会影响彼此的执行；例如，在网页服务中。虽然这种排队方式可用于平滑请求的瞬态爆发，但它承认当命令继续以平均比处理速度更快的速度到达时，工作队列无限制增长的可能性。
        Bounded queues. 有界队列（例如 ArrayBlockingQueue ）在与有限的 maximumPoolSizes 一起使用时有助于防止资源耗尽，但可能更难调整和控制。
            队列大小和最大池大小可以相互权衡：使用大队列和小池可以最大限度地减少 CPU 使用率、操作系统资源和上下文切换开销，但会导致吞吐量人为降低。
            如果任务频繁阻塞（例如，如果它们受 I/O 限制），系统可能会为比您允许的更多的线程安排时间。使用小队列通常需要更大的池大小，这会使 CPU 更忙，但可能会遇到无法接受的调度开销，这也会降低吞吐量。
    拒绝的任务
        当 Executor 关闭时，在方法 execute(Runnable) 中提交的新任务将是 rejected，并且当 Executor 对最大线程和工作队列容量使用有限边界并且饱和时。
        在任何一种情况下，execute 方法都会调用其 RejectedExecutionHandler 的 RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) 方法。
        提供了四种预定义的处理程序策略：
            在默认的 ThreadPoolExecutor.AbortPolicy 中，处理程序在拒绝时抛出运行时 RejectedExecutionException 。
            在 ThreadPoolExecutor.CallerRunsPolicy 中，调用 execute 的线程本身运行任务。这提供了一种简单的反馈控制机制，可以减慢提交新任务的速度。
            在 ThreadPoolExecutor.DiscardPolicy 中，无法执行的任务会被简单地丢弃。此策略仅适用于从不依赖任务完成的极少数情况。
            在 ThreadPoolExecutor.DiscardOldestPolicy 中，如果执行器未关闭，工作队列头部的任务将被丢弃，然后重试执行（可能会再次失败，导致重复。）这种策略很少被接受。
                在几乎所有情况下，您还应该取消任务以在任何等待其完成的组件中导致异常，和/或记录失败，如 ThreadPoolExecutor.DiscardOldestPolicy 文档中所示。
        可以定义和使用其他类型的 RejectedExecutionHandler 类。这样做需要格外小心，尤其是当策略设计为仅在特定容量或排队策略下工作时。
         */
        // 参数如果比较多的时候 合理换行
        ExecutorService threadPool = new ThreadPoolExecutor(
                10,
                10,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10)
        );


        /*
            int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                // 核心执行线程的地方 最终会执行到start() 开启一个线程
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            else if (!addWorker(command, false))
                reject(command);





         */
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(1);
            }
        });
        // 关闭线程池 线程使用完毕 千万要记得调用此方法 关闭线程
        threadPool.shutdown();


    }
}
